#include <ctype.h>
#include <algorithm>
#include <vector>
#include <events/common_log.h>
#include "sf_string.h"

#define QLatin1Char(a) a

#ifdef GEN_Printf
#undef GEN_Printf
#undef SLOG

#define GEN_Printf(f, fmt, ...)
#define SLOG(f, fmt, ...)
#endif

using namespace std;
SFString::SFString()
    : string("")
{

}

SFString::SFString(int size, int)
{
    this->resize(size);
}

SFString::SFString(const char *str)
    : string(str ? str : "")
{
}

SFString::SFString(const char *str, int len)
    : string(str ? str : "", 0, len)
{
}

SFString::SFString(const string &str)
    : string(str)
{
}

bool SFString::contains(char ch)
{
    for (char c : *this)
    {
        if (ch == c) return true;
    }
    return false;
}

/**
 * @brief SFString::contains
 * @param str
 * @return
 * @warning find 查找str相匹配的；find_first_of 查找this中包含有str中的字符位置
 */
bool SFString::contains(const SFString &str)
{
#if 0
    int ret = this->find(str);

    SLOG(LOG_INFO, "%d", ret);
#else
    return (std::string::npos == this->find(str)) ? false : true;
#endif
}

bool SFString::isValid() const
{
    return !this->empty();
}

SFStringList SFString::split(SFString const &tmp1)
{
    SFStringList lst;
    SFString tmp = *this;

    const char *delim = &tmp1.front();
    char *start = &tmp.front();
    char *__save_ptr, *str;

    for (str = start; ; str = NULL)
    {
        char *subtoken = strtok_r(str, delim, &__save_ptr);
        if (subtoken == NULL)
        {
            break;
        }

        lst.push_back(subtoken);
    }

    return lst;
}

SFStringList SFString::split(const SFString &str) const
{
    return const_cast<SFString *>(this)->split(str);
}

SFStringVector SFString::splitv(char ch)
{
    return this->splitv(std::string(1, ch));
}

SFStringVector SFString::splitv(char ch) const
{
    return const_cast<SFString *>(this)->splitv(ch);
}

SFStringVector SFString::splitv(SFString const &tmp1)
{
    SFStringVector lst;
    SFString tmp = *this;

    const char *delim = &tmp1.front();
    char *start = &tmp.front();
    char *__save_ptr, *str;

    for (str = start; ; str = NULL)
    {
        char *subtoken = strtok_r(str, delim, &__save_ptr);
        if (subtoken == NULL)
        {
            break;
        }

        lst.push_back(subtoken);
    }

    return lst;
}

SFStringVector SFString::splitv(const SFString &str) const
{
    return const_cast<SFString *>(this)->splitv(str);
}



struct ArgEscapeData
{
    int min_escape;            // lowest escape sequence number
    int occurrences;           // number of occurrences of the lowest escape sequence number
    int locale_occurrences;    // number of occurrences of the lowest escape sequence number that
    // contain 'L'
    int escape_len;            // total length of escape sequences which will be replaced
};

typedef char QChar;
inline static int digitValue(QChar ch)
{
    return (ch >= '0' && ch <= '9') ? ch - '0' : -1;
}
static ArgEscapeData findArgEscapes(const SFString &s)
{
    const QChar *uc_begin = s.c_str();
    const QChar *uc_end = uc_begin + s.size();

    ArgEscapeData d;

    d.min_escape = 2147483647;
    d.occurrences = 0;
    d.escape_len = 0;
    d.locale_occurrences = 0;

    const QChar *c = uc_begin;
    while (c != uc_end)
    {
        while (c != uc_end && *c != '%')
        {
            ++c;
        }

        if (c == uc_end)
        {
            GEN_Printf(LOG_DEBUG, "%d", d.occurrences);
            break;
        }
        const QChar *escape_start = c;
        if (++c == uc_end)
        {
            GEN_Printf(LOG_DEBUG, "%d", d.occurrences);
            break;
        }

        bool locale_arg = false;
        if (*c == 'L')
        {
            locale_arg = true;
            if (++c == uc_end)
            {
                GEN_Printf(LOG_DEBUG, "%d", d.occurrences);
                break;
            }
        }

        int escape = digitValue(*c);
        GEN_Printf(LOG_DEBUG, "escape = %d", escape);
        if (escape == -1)
        {
            GEN_Printf(LOG_DEBUG, "%d", d.occurrences);
            continue;
        }

        ++c;

        if (c != uc_end)
        {
            int next_escape = digitValue(*c);
            if (next_escape != -1)
            {
                escape = (10 * escape) + next_escape;
                ++c;
            }
        }

        GEN_Printf(LOG_DEBUG, "escape = %d, min_escape = %d", escape, d.min_escape);
        if (escape > d.min_escape)
        {
            GEN_Printf(LOG_DEBUG, "%d", d.occurrences);
            continue;
        }

        if (escape < d.min_escape)
        {
            d.min_escape = escape;
            d.occurrences = 0;
            d.escape_len = 0;
            d.locale_occurrences = 0;
        }

        ++d.occurrences;
        if (locale_arg)
        {
            ++d.locale_occurrences;
        }
        d.escape_len += c - escape_start;
    }
    return d;
}

#define qAbs std::abs
#define qMax(a, b) ((a) > (b) ? (a) : (b))
static SFString replaceArgEscapes(const SFString &s, const ArgEscapeData &d, int field_width,
                                 const SFString &arg, const SFString &larg, QChar fillChar = QLatin1Char(' '))
{
    const QChar *uc_begin = s.c_str();
    const QChar *uc_end = uc_begin + s.size();

    int abs_field_width = qAbs(field_width);
    int result_len = s.length()
            - d.escape_len
            + (d.occurrences - d.locale_occurrences)
            *qMax(abs_field_width, (int)arg.length())
            + d.locale_occurrences
            *qMax(abs_field_width, (int)larg.length());

    SFString result(result_len, 1);
    QChar *result_buff = (QChar*) &result.front();

    QChar *rc = result_buff;
    const QChar *c = uc_begin;
    int repl_cnt = 0;
    SLOG(LOG_DEBUG, "%p", c);
    while (c != uc_end)
    {
        /* We don't have to check if we run off the end of the string with c,
           because as long as d.occurrences > 0 we KNOW there are valid escape
           sequences. */

        const QChar *text_start = c;

        SLOG(LOG_DEBUG, "%p", c);
        while (*c != '%')
        {
            ++c;
        }

        const QChar *escape_start = c++;

        bool locale_arg = false;
        if (*c == 'L')
        {
            locale_arg = true;
            ++c;
        }

        int escape = digitValue(*c);
        if (escape != -1)
        {
            if (c + 1 != uc_end && digitValue(*(c + 1)) != -1)
            {
                escape = (10 * escape) + digitValue(*(c + 1));
                ++c;
            }
        }

        if (escape != d.min_escape)
        {
            memcpy(rc, text_start, (c - text_start)*sizeof(QChar));
            rc += c - text_start;
        } else
        {
            ++c;

            memcpy(rc, text_start, (escape_start - text_start)*sizeof(QChar));
            rc += escape_start - text_start;

            uint pad_chars;
            if (locale_arg)
            {
                pad_chars = qMax(abs_field_width, (int)larg.length()) - larg.length();
            } else
            {
                pad_chars = qMax(abs_field_width, (int)arg.length()) - arg.length();
            }

            if (field_width > 0)
            { // left padded
                for (uint i = 0; i < pad_chars; ++i)
                {
                    *(rc++) = fillChar;
                }
            }

            if (locale_arg)
            {
                memcpy(rc, larg.c_str(), larg.length()*sizeof(QChar));
                rc += larg.length();
            } else
            {
                memcpy(rc, arg.c_str(), arg.length()*sizeof(QChar));
                rc += arg.length();
            }

            if (field_width < 0)
            { // right padded
                for (uint i = 0; i < pad_chars; ++i)
                {
                    *(rc++) = fillChar;
                }
            }

            if (++repl_cnt == d.occurrences)
            {
                memcpy(rc, c, (uc_end - c)*sizeof(QChar));
                rc += uc_end - c;
                SF_ASSERT(rc - result_buff == result_len);
                c = uc_end;
            }
        }
    }
    SF_ASSERT(rc == result_buff + result_len);

    return result;
}

SFString SFString::arg(const SFString &a, int fieldWidth, char fillChar) const
{
    ArgEscapeData d = findArgEscapes(*this);

    if (d.occurrences == 0)
    {
        SLOG(LOG_WARN, "SFString::arg: Argument missing: %s, %s", this->data(), a.data());
        return *this;
    }

    return replaceArgEscapes(*this, d, fieldWidth, a, a, fillChar);
}


static int getEscape(const QChar *uc, int *pos, int len, int maxNumber = 999)
{
    int i = *pos;
    ++i;
    if (i < len && uc[i] == QLatin1Char('L'))
    {
        ++i;
    }
    if (i < len)
    {
        int escape = uc[i] - '0';
        if (uint(escape) >= 10U)
        {
            return -1;
        }
        ++i;
        while (i < len)
        {
            int digit = uc[i] - '0';
            if (uint(digit) >= 10U)
            {
                break;
            }
            escape = (escape * 10) + digit;
            ++i;
        }
        if (escape <= maxNumber)
        {
            *pos = i;
            return escape;
        }
    }
    return -1;
}

namespace {
struct SFStringRef {
    inline SFStringRef() : m_string(nullptr), m_position(0), m_size(0) {}

    inline SFStringRef(const SFString *aString, int aPosition, int aSize)
            :m_string(aString), m_position(aPosition), m_size(aSize){}

    inline SFStringRef(const SFString *aString)
        :m_string(aString), m_position(0), m_size(aString ? aString->size() : 0){}

    inline const SFString *string() const { return m_string; }
    inline int position() const { return m_position; }
    inline int size() const { return m_size; }
    inline int count() const { return m_size; }
    inline int length() const { return m_size; }
    inline const QChar *data() const { return unicode(); }
    inline const QChar *constData() const {  return unicode(); }

    inline const QChar *unicode() const
    {
        if (!m_string)
        {
            return reinterpret_cast<const QChar *>("");
        }
        return m_string->c_str() + m_position;
    }

    const SFString *m_string;
    int m_position;
    int m_size;
};
struct Part
{
    Part() : stringRef(), number(0) {}
    Part(const SFString &s, int pos, int len, int num = -1)
        : stringRef(&s, pos, len), number(num) {}

    SFStringRef stringRef;
    int number;
};
} // unnamed namespace

namespace {

enum { ExpectedParts = 32 };

typedef std::vector<Part> ParseResult;
typedef std::vector<int> ArgIndexToPlaceholderMap;

static ParseResult parseMultiArgFormatString(const SFString &s)
{
    ParseResult result;

    const QChar *uc = s.c_str();
    const int len = s.size();
    const int end = len - 1;
    int i = 0;
    int last = 0;

    while (i < end)
    {
        if (uc[i] == QLatin1Char('%'))
        {
            int percent = i;
            int number = getEscape(uc, &i, len);
            if (number != -1)
            {
                if (last != percent)
                {
                    result.push_back(Part(s, last, percent - last)); // literal text (incl. failed placeholders)
                }
                result.push_back(Part(s, percent, i - percent, number));  // parsed placeholder
                last = i;
                continue;
            }
        }
        ++i;
    }

    if (last < len)
    {
        result.push_back(Part(s, last, len - last)); // trailing literal text
    }

    return result;
}

static ArgIndexToPlaceholderMap makeArgIndexToPlaceholderMap(const ParseResult &parts)
{
    ArgIndexToPlaceholderMap result;

    for (ParseResult::const_iterator it = parts.begin(), end = parts.end(); it != end; ++it)
    {
        if (it->number >= 0)
        {
            result.push_back(it->number);
        }
    }

    std::sort(result.begin(), result.end());
    result.erase(std::unique(result.begin(), result.end()),
                 result.end());

    return result;
}

static int resolveStringRefsAndReturnTotalSize(ParseResult &parts, const ArgIndexToPlaceholderMap &argIndexToPlaceholderMap, const SFString *args[])
{
    int totalSize = 0;
    for (ParseResult::iterator pit = parts.begin(), end = parts.end(); pit != end; ++pit) {
        if (pit->number != -1)
        {
            const ArgIndexToPlaceholderMap::const_iterator ait
                    = std::find(argIndexToPlaceholderMap.begin(), argIndexToPlaceholderMap.end(), pit->number);
            if (ait != argIndexToPlaceholderMap.end())
            {
                pit->stringRef = SFStringRef(args[ait - argIndexToPlaceholderMap.begin()]);
            }
        }
        totalSize += pit->stringRef.size();
    }
    return totalSize;
}

} // unnamed namespace

SFString SFString::multiArg(int numArgs, const SFString **args) const
{
     // Step 1-2 above
    ParseResult parts = parseMultiArgFormatString(*this);

    // 3-4
    ArgIndexToPlaceholderMap argIndexToPlaceholderMap = makeArgIndexToPlaceholderMap(parts);

    if ((int)argIndexToPlaceholderMap.size() > numArgs) // 3a
    {
        argIndexToPlaceholderMap.resize(numArgs);
    } else if ((int)argIndexToPlaceholderMap.size() < numArgs) // 3b
    {
        GEN_Printf(LOG_WARN, "SFString::arg: %d argument(s) missing in %s",
                 numArgs - argIndexToPlaceholderMap.size(), data());
    }

    // 5
    const int totalSize = resolveStringRefsAndReturnTotalSize(parts, argIndexToPlaceholderMap, args);

    // 6:
    SFString result(totalSize, 1);
    QChar *out = &result.front();

    for (ParseResult::const_iterator it = parts.begin(), end = parts.end(); it != end; ++it) {
        if (const int sz = it->stringRef.size()) {
            memcpy(out, it->stringRef.constData(), sz * sizeof(QChar));
            out += sz;
        }
    }

    return result;
}

SFString SFString::arg(const SFString &a1, const SFString &a2) const
{
    const SFString *args[2] = { &a1, &a2 };
    return multiArg(2, args);
}

SFString SFString::arg(const SFString &a1, const SFString &a2, const SFString &a3) const
{
    const SFString *args[3] = { &a1, &a2, &a3 };
    return multiArg(3, args);
}

SFStringList SFString::split(char ch)
{
    return this->split(std::string(1, ch));
}

SFStringList SFString::split(char ch) const
{
    return const_cast<SFString *>(this)->split(ch);
}

#define  TOSTRING(size, fmt) \
    std::string tmp; \
    tmp.resize(size); \
    tmp.resize(snprintf(&tmp.front(), 31, fmt, val)); \
    return tmp;

#define  TOSTRING_SWI(size, fmt, fmt16) \
    std::string tmp; \
    tmp.resize(size); \
    tmp.resize(snprintf(&tmp.front(), 31, (10 == base) ? fmt : fmt16, val)); \
    return tmp;

SFString SFString::number(int val, int base)
{
    TOSTRING_SWI(32, "%d", "0x%x")
}

SFString SFString::number(unsigned int val, int base)
{
    TOSTRING_SWI(32, "%u", "0x%x")
}

SFString SFString::number(long val, int base)
{
    TOSTRING_SWI(64, "%ld", "0x%lx")
}

SFString SFString::number(unsigned long val, int base)
{
    TOSTRING_SWI(64, "%lu", "0x%lx")
}

SFString SFString::number(long long val, int base)
{
    std::string tmp;

    tmp.resize(64);
    const char *fmt = (10 == base) ? "%lld" : "%llx";

    tmp.resize(snprintf(&tmp.front(), 31, fmt, val));

    return tmp;
}

SFString SFString::number(unsigned long long val, int base)
{
    std::string tmp;

    tmp.resize(64);
    const char *fmt = (10 == base) ? "%llu" : "%llx";

    tmp.resize(snprintf(&tmp.front(), 31, fmt, val));

    return tmp;
}

SFString SFString::number(double val, char /*f*/, int /*prec*/)
{
    TOSTRING(64, "%g")
}

bool SFString::toBool(bool def)
{
    return empty() ? def : ((0 == strcmp(this->data(), "1")
                             || 0 == strcasecmp(this->data(), "true")) ? true : false);
}

uint SFString::toUInt(unsigned int def, int scale) const
{
    return this->empty() ? def : strtoul(this->data(), NULL, scale);
}

int SFString::toInt(int def, int scale) const
{
    return this->empty() ? def : strtol(this->data(), NULL, scale);
}

long SFString::toLong(long def, int scale) const
{
    return this->empty() ? def : strtol(this->data(), NULL, scale);
}

unsigned long SFString::toULong(unsigned long def, int scale) const
{
    return this->empty() ? def : strtoul(this->data(), NULL, scale);
}

float SFString::toFloat(float def) const
{
    return this->empty() ? def : strtof(this->data(), NULL);
}

double SFString::toDouble(double def) const
{
    return this->empty() ? def : atof(this->data());
}

long long SFString::toLongLong(long long def, int scale) const
{
    return this->empty() ? def : strtoll(this->data(), NULL, scale);
}

unsigned long long SFString::toULongLong(unsigned long long def, int scale) const
{
    return this->empty() ? def : strtoull(this->data(), NULL, scale);
}

typedef char Char;
#define isSpace isspace
static inline void trimmed_helper_positions(const Char *&begin, const Char *&end)
{
    // skip white space from start
    while (begin < end && isSpace(*begin))
    {
        begin++;
    }
    // skip white space from end
    if (begin < end)
    {
        while (begin < end && isSpace(end[-1]))
        {
            end--;
        }
    }
}

template<typename StringType> static inline StringType trimmed_helper(StringType &str)
{
    const Char *begin = &str.front();
    const Char *end   = &str.back();

    trimmed_helper_positions(begin, end);

    if (begin == &str.front() && end == &str.back())
    {
        return str;
    }

    return StringType(begin, end - begin);
}

/**
 * @brief SFString::trimmed
 * @return 返回值为去除了开头和结尾的空白字符串，这里的空白指QChar::isSpace()返回值为true，比如'\t','\n','\v','\f','\r'和' ';
 * @note 完全复制了Qt中这个函数的代码
 */
SFString SFString::trimmed()
{
    return trimmed_helper(*this);
}
SFString SFString::trimmed() const
{
    return trimmed_helper(*const_cast<SFString *>(this));
}

static SFString simplified_helper(SFString &str)
{
    if (str.isEmpty())
    {
        return str;
    }
    const char *src = &str.front();
    const char *end = &str.back();
    SFString result;
    result.resize(str.size());

    char *dst = const_cast<char *>(&result.front());
    char *ptr = dst;
    bool unmodified = true;

    while(1)
    {
        while (src != end && isspace(*src))
        {
            ++src;
        }
        while (src != end && !isspace(*src))
        {
            *ptr++ = *src++;
        }
        if (src == end)
        {
            break;
        }
        if (*src != ' ')
        {
            unmodified = false;
        }
        *ptr++ = ' ';
    }

    if (ptr != dst && ptr[-1] == ' ')
    {
        --ptr;
    }

    int newlen = ptr - dst;
    if (newlen == (int)str.size() && unmodified)
    {
        // nothing happened, return the original
        return str;
    }
    result.resize(newlen);
    return result;

}

/**
 * @brief SFString::simplified
 * @return 返回字符串开头和结尾除去空白的字符串，并且内部的空白字符也去掉，这里的空白字符和上面的一样。
 * @note 完全复制了Qt中这个函数的代码
 */
SFString SFString::simplified()
{
    return simplified_helper(*this);
}

SFString SFString::simplified() const
{
    return simplified_helper(*const_cast<SFString *>(this));
}

SFString SFString::basename()
{
    SFString::size_type ret = this->find_last_of('/');
    GEN_Printf(LOG_DEBUG, "ret: %u", (uint32_t)ret);
    if (ret != SFString::npos)
    {
        return this->substr(ret + 1);
    }
    return *this;
}

SFString SFString::dirname()
{
    SFString::size_type ret = this->find_last_of('/');
    GEN_Printf(LOG_DEBUG, "ret: %u", (uint32_t)ret);
    if (ret != SFString::npos)
    {
        return (0 == ret) ? "/" : this->substr(0, ret);
    }
    return SFString();
}
SFString SFString::mid(int i, int pos)
{
   return SFString(this->substr(i, pos));
}

void SFString::toUpper()
{
    std::string &self = *this;
    for (int i = 0; i < (int)this->size(); ++i)
    {
        char ch = self[i];
        if (islower(ch))
        {
            self[i] = toupper(ch);
        }
    }
}

void SFString::toLower()
{
    std::string &self = *this;
    for (int i = 0; i < (int)this->size(); ++i)
    {
        char ch = self[i];
        if (isupper(ch))
        {
            self[i] = tolower(ch);
        }
    }
}

SFString SFString::format(const char *fmt, ...)
{
    SFString buffer(32, 0);
    char *bPos = (char *)&buffer.front();

    va_list args, ap;
    va_start(args, fmt);
    va_copy(ap, args);
    int nwrite = vsnprintf(bPos, buffer.size(), fmt, ap);

    GEN_Printf(LOG_DEBUG, "nwrite: %d, size: %d", nwrite, (int)buffer.size());
    if (nwrite < 0)
    {
        return SFString();
    } else if (nwrite >= (int)buffer.size())
    {
        buffer.resize(nwrite + 1);
        va_copy(ap, args);
        bPos = (char *)&buffer.front();
        nwrite = vsnprintf(bPos, buffer.size(), fmt, ap);
    }

    va_end(args);

    buffer.resize(nwrite);
    return buffer;
}

SFByteArray SFByteArray::mid(int pos, int len) const
{
    return string(this->data() + pos, len >= 0 ? len : this->size());
}

typedef unsigned char uchar;
#define toHexLower(i) "0123456789abcdef"[(i)]
SFByteArray SFByteArray::toHex() const
{
    return toHex('\0');
}

SFByteArray SFByteArray::toHex(char separator) const
{
    if (this->empty()) return SFByteArray();

    const int length = separator ? (this->size() * 3 - 1) : (this->size() * 2);

    SFByteArray hex(length, 1);
    char *hexData = &hex.front();
    const uchar *data = (const uchar *)this->data();

    for (int i = 0, o = 0; i < (int)this->size(); ++i)
    {
        hexData[o++] = toHexLower(data[i] >> 4);
        hexData[o++] = toHexLower(data[i] & 0xf);

        if ((separator) && (o < length))
        {
            hexData[o++] = separator;
        }
    }

    return hex;
}

/**
 * @brief SFByteArray::remove
 * @param pos
 * @param len
 * @return 并返回对该数组的引用。
 * @details 从索引位置pos开始从数组中移除len bytes，
 */
SFByteArray &SFByteArray::remove(int pos, int len)
{
    if (len <= 0  || uint(pos) >= uint(this->size()))
    {
        return *this;
    }
    // detach();
    if (len >= int (this->size()) - pos)
    {
        resize(pos);
    } else
    {
        char *start = &this->front();
        memmove(start + pos, start + pos + len, this->size() - pos - len);
        resize(this->size() - len);
    }
    return *this;
}


